/**
 * @file hs_rasterdata.h
 * @author iam002
 * @brief RasterData模板类
 * @version 1.0
 * @date 2024-10-15
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#ifndef __HS_RASTERDATA_H__
#define __HS_RASTERDATA_H__

#include "hs_logger.h"
#include "hs_rasterview.h"

namespace hs
{

namespace raster
{

/**
 * @brief RasterData模板类
 * 
 * @tparam DataType 数据类型
 */
template<typename DataType>
class RasterData
{

public:
    
    /**
     * @brief 默认构造函数
     * 
     * @param is_row_major 是否行优先存储, 默认为true
     */
    explicit RasterData(bool is_row_major = true)
        : m_p_rawdata(nullptr), m_alloc_size(0), m_p_view(nullptr)
    {
        allocView(is_row_major);
    }


    /**
     * @brief 构造函数
     * 
     * @param size_x 图宽, x方向指水平方向
     * @param size_y 图高, y方向指竖直方向
     * @param is_row_major 数据是否按行优先存储, 默认为true 
     */
    RasterData(int size_x, int size_y, bool is_row_major = true)
        : m_p_rawdata(nullptr), m_alloc_size(0), m_p_view(nullptr)
    {
        init(size_x, size_y, is_row_major);
    }


    /**
     * @brief 析构函数
     * 
     */
    ~RasterData()
    {
        release();

        if (m_p_view) {
            delete [] m_p_view;
            m_p_view = nullptr;
        }
    }


    /**
     * @brief 拷贝构造函数, 输入对象交出所有权
     * 
     * @param obj RasterData输入对象
     */
    RasterData(RasterData & obj)
        : m_p_rawdata(nullptr), m_alloc_size(0), m_p_view(nullptr)
    {
        allocView(obj.view().isRowMajor());

        m_p_rawdata = obj.m_p_rawdata;
        m_alloc_size = obj.m_alloc_size;
        (*m_p_view) = (*obj.m_p_view);

        obj.m_p_rawdata = nullptr;
        obj.m_alloc_size = 0;
        obj.m_p_view->clear();
    }


    /**
     * @brief 移动构造函数, 输入对象交出所有权
     * 
     * @param obj RasterData输入对象
     */
    RasterData(RasterData && obj)
        : m_p_rawdata(nullptr), m_alloc_size(0), m_p_view(nullptr)
    {
        allocView(obj.view().isRowMajor());

        m_p_rawdata = obj.m_p_rawdata;
        m_alloc_size = obj.m_alloc_size;
        (*m_p_view) = (*obj.m_p_view);

        obj.m_p_rawdata = nullptr;
        obj.m_alloc_size = 0;
        obj.m_p_view->clear();
    }

    /**
     * @brief 初始化RasterData, 此函数会重新分配内存
     * 
     * @param size_x 图宽, x方向指水平方向
     * @param size_y 图高, y方向指竖直方向
     * @param is_row_major 数据是否按行优先存储, 默认为true
     */
    void init(int size_x, int size_y, bool is_row_major = true)
    {
        allocView(is_row_major);
        release();

        if (size_x <= 0 || size_y <= 0) {
            LOG_FATAL("hs::raster::RasterData::init Fatal Error: size_x(" $ size_x $ ") <= 0 or size_y(" $ size_y $ ") <= 0\n");
        }

        try {
            m_alloc_size = size_x * size_y;
            m_p_rawdata = new DataType[m_alloc_size];
            if (m_p_rawdata == nullptr) {
                LOG_FATAL("hs::raster::RasterData::init Fatal Error: allocate for m_p_rawdata failed!\n");
            }
        }
        catch (const std::bad_alloc & e) {
            LOG_FATAL("hs::raster::RasterData::init Fatal Error: allocate for m_p_rawdata failed: " $ e.what() $ std::endl);
        }

        m_p_view->init(size_x, size_y, m_p_rawdata);
    }


    /**
     * @brief 释放分配的内存
     * 
     */
    void release()
    {
        if (m_p_rawdata) {
            delete [] m_p_rawdata;
            m_p_rawdata = nullptr;
            m_alloc_size = 0;
        }

        m_p_view->clear();
    }


    /**
     * @brief 赋值构造函数, 输入对象交出所有权
     * 
     * @param obj RasterData输入对象
     * @return RasterData& 新RasterData对象
     */
    RasterData & operator=(RasterData & obj)
    {
        if (&obj == this) {
            return *this;
        }

        release();

        m_p_rawdata = obj.m_p_rawdata;
        m_alloc_size = obj.m_alloc_size;
        (*m_p_view) = (*obj.m_p_view);

        obj.m_p_rawdata = nullptr;
        obj.m_alloc_size = 0;
        obj.m_p_view->clear();

        return *this;
    }


    /**
     * @brief 赋值移动构造函数, 输入对象交出所有权
     * 
     * @param obj RasterData输入对象
     * @return RasterData& 新RasterData对象
     */
    RasterData & operator=(RasterData && obj)
    {
        if (&obj == this) {
            return *this;
        }

        release();

        m_p_rawdata = obj.m_p_rawdata;
        m_alloc_size = obj.m_alloc_size;
        (*m_p_view) = (*obj.m_p_view);

        obj.m_p_rawdata = nullptr;
        obj.m_alloc_size = 0;
        obj.m_p_view->clear();

        return *this;
    }


    /**
     * @brief 拷贝RasterData对象(重新分配内存)
     * 
     * @param obj 拷贝源
     */
    void copyFrom(const RasterData & obj)
    {
        release();

        init(obj.m_p_view->sizeX(), obj.m_p_view->sizeY(), obj.m_p_view->isRowMajor());

        for (int i = 0; i < obj.m_p_view->numel(); ++i) {
            m_p_rawdata[i] = obj.m_p_rawdata[i];
        }

        if (obj.m_p_view->hasNodata()) {
            m_p_view->setNodata(obj.m_p_view->nodata());
        }
        else {
            m_p_view->setDefaultNodata();
        }
    }


    /**
     * @brief 返回 RasterView 对象
     * 
     * @return RasterView<DataType>& 
     */
    RasterView<DataType> & view()
    {
        return (*m_p_view);
    }


    /**
     * @brief 返回 RasterView 对象
     * 
     * @return RasterView<DataType>& 
     */
    const RasterView<DataType> & view() const
    {
        return (*m_p_view);
    }


    /**
     * @brief 获取平面索引坐标(x,y)上的值, 注意不检查索引是否越界
     * 
     * @param x 平面x方向索引
     * @param y 平面y方向索引
     * @return const DataType& 平面索引坐标(x,y)的取值
     */
    const DataType & operator()(int x, int y) const
    {
        return m_p_view->operator()(x, y);
    }


    /**
     * @brief 获取平面索引坐标(x,y)上的值, 注意不检查索引是否越界
     * 
     * @param x 平面x方向索引
     * @param y 平面y方向索引
     * @return DataType& 平面索引坐标(x,y)的取值
     */
    DataType & operator()(int x, int y)
    {
        return m_p_view->operator()(x, y);
    }


    /**
     * @brief 改变栅格大小, 新栅格大小不能超过原有大小
     * 
     * @param new_size_x 新图宽
     * @param new_size_y 新图高
     * @return true 操作成功
     * @return false 操作失败
     */
    bool reshape(int new_size_x, int new_size_y)
    {
        if (new_size_x * new_size_y > m_alloc_size) {
            LOG_ERROR("hs::raster::RasterDatga::reshape Error: new_size_x * new_size_y (" $ new_size_x * new_size_y $  ") > m_alloc_size(" $ m_alloc_size $ ")!\n");
            return false;
        }
        m_p_view->_setSize(new_size_x, new_size_y);
        return true;
    }

protected:

    /**
     * @brief 为m_p_view分配内存, m_p_view只在创建实例分配一次，直至实例被销毁
     * 
     * @param is_row_major 是否行优先存储
     */
    void allocView(bool is_row_major)
    {
        if (m_p_view == nullptr) {
            try {
                if (is_row_major) {
                    m_p_view = new RasterView<DataType>();
                }
                else {
                    m_p_view = new RasterColView<DataType>();
                }
                if (m_p_view == nullptr) {
                    LOG_FATAL("hs::raster::RasterData::allocView Fatal Error: allocate for m_p_view failed!\n");
                }
            }
            catch (const std::bad_alloc & e) {
                LOG_FATAL("hs::raster::RasterData::allocView Fatal Error: allocate for m_p_view failed: " $ e.what() $ std::endl);
            }
        }
        else {
            if (m_p_view->isRowMajor() != is_row_major) {
                delete [] m_p_view;
                m_p_view = nullptr;
                allocView(is_row_major);
            }
        }
    }

protected:
    /// @brief RasterView类指针
    RasterView<DataType>* m_p_view;

    /// @brief 原始数据指针
    DataType* m_p_rawdata;

    /// @brief 实际分配的内存大小
    int m_alloc_size;
};

} // end namespace raster

} // end namespace hs

#endif
